package com.ljx.visitorMode;


import lombok.Data;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * 访问者模式
 *
 * 定义：
 * 封装一些作用于某种数据结构中的各元素的操作，它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作
 *
 * 优点：
 * @ 扩展性好
 * 在不修改对象结构中的元素的情况下，为对象结构中的元素添加新的功能。
 * @ 复用性好
 * 通过访问者来定义整个对象结构通用的功能，从而提高复用程度。
 * @ 分离无关行为
 * 通过访问者来分离无关的行为，把相关的行为封装在一起，构成一个访问者，这样每一个访问者的功能都比较单一。
 *
 * 缺点：
 * @ 对象结构变化很困难
 * 在访问者模式中，每增加一个新的元素类，都要在每一个具体访问者类中增加相应的具体操作，这违背了“开闭原则”。
 * @ 违反了依赖倒置原则
 * 访问者模式依赖了具体类，而没有依赖抽象类
 *
 * 使用场景：
 * 对象结构相对稳定，但其操作算法经常变化的程序。
 * 对象结构中的对象需要提供多种不同且不相关的操作，而且要避免让这些操作的变化影响对象的结构
 *
 * @作者 LJX
 * @日期 2022/12/26 16:30
 */
public class VisitorModeTest {

    public static void main(String[] args) {
        //创建家
        Home home = new Home();

        //购置宠物
        home.addPets(new Cat());
        home.addPets(new Dog());

        //主人
        Person master = new Master();
        home.action(master);
        //客人
        Person someone = new Someone();
        home.action(someone);
    }

}

/**
 * 抽象元素，宠物
 */
interface Pets{

    /**
     * 宠物与人互动的方法
     */
    void interact(Person person);

}

/**
 * 具体元素，狗
 */
class Dog implements Pets{

    @Override
    public void interact(Person person) {
        person.interact(this);
        System.out.println("狗和人互动");
    }
}

/**
 * 具体元素，猫
 */
class Cat implements Pets{

    @Override
    public void interact(Person person) {
        person.interact(this);
        System.out.println("猫和人互动");
    }
}

/**
 * 抽象访问者，人类
 */
interface Person{

    /**
     * 与宠物狗互动的方法
     */
    void interact(Dog dog);

    /**
     * 与宠物猫互动的方法
     */
    void interact(Cat cat);

}

/**
 * 具体访问者，主人
 */
class Master implements Person{

    @Override
    public void interact(Dog dog) {
        System.out.println("主人遛狗");
    }

    @Override
    public void interact(Cat cat) {
        System.out.println("主人遛猫");
    }
}

/**
 * 具体访问者，客人
 */
class Someone implements Person{

    @Override
    public void interact(Dog dog) {
        System.out.println("客人喂狗");
    }

    @Override
    public void interact(Cat cat) {
        System.out.println("客人喂猫");
    }
}

/**
 * 结构类，家
 */
@Data
class Home{

    private List<Pets> petsList = new ArrayList<>();

    /**
     * 人类和宠物互动
     * @param person
     */
    public void action(Person person){

        for (Pets pets : petsList) {
            pets.interact(person);
        }

    }

    /**
     * 添加宠物
     * @param pets
     */
    public void addPets(Pets pets){
        petsList.add(pets);
    }


}
